package com.sicilin.object.service;

import com.sicilin.common.exception.BusinessException;
import com.sicilin.common.exception.ServiceException;
import com.sicilin.common.page.PageUtils;
import com.sicilin.dao.ObjectDao;
import com.sicilin.object.dto.ObjectDTO;
import com.sicilin.object.enums.ObjectTypeEnum;
import com.sicilin.po.TCObject;
import com.sicilin.object.exception.ObjectServiceException;
import com.sicilin.object.util.ObjectUtils;
import com.sicilin.system.login.dto.LoginUser;
import com.sicilin.system.login.service.LoginService;
import com.sicilin.system.user.Admin;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;

@Service
@Transactional(readOnly = true)
public class ObjectService {

    @Autowired(required = false)
    private ObjectDao objectDao;

    @Autowired
    private Admin admin;

    @Autowired
    private LoginService loginService;

    @Transactional(rollbackFor = {Exception.class},propagation = Propagation.REQUIRED)
    public TCObject saveObjectFatherType(String objectCode,String objectName,int state) throws ServiceException,BusinessException{
        return this.saveObject(objectCode,objectName,0, ObjectTypeEnum.FATHER.getType(),state,admin.getCompanyId());
    }

    @Transactional(rollbackFor = {Exception.class},propagation = Propagation.REQUIRED)
    public TCObject saveObjectSonType(String objectCode,String objectName,int parentId,int state,int companyId,ObjectTypeEnum typeEnum) throws ServiceException,BusinessException{
        if(parentId <= 0){throw new ObjectServiceException("Invalid parentId! It's must be greater than 0!");}
        return this.saveObject(objectCode,objectName,parentId,typeEnum.getType(),state,companyId);
    }

    public List<TCObject> searchObjectFatherType(String searchText)throws ObjectServiceException{
        return objectDao.searchObjectType(searchText);
    }

    public TCObject findTCObjectById(int objectId) throws ObjectServiceException{
        return objectDao.getTCObjectbyId(objectId);
    }

    @Transactional(rollbackFor = {Exception.class},propagation = Propagation.REQUIRED)
    public TCObject updateTCObjectByidWidthType(int objectId, String objectCode, String objectName, Integer state, ObjectTypeEnum updateType) throws ObjectServiceException,BusinessException{
        if(objectId <= 0){throw new ObjectServiceException("Invalid objectId! It's must be greater than 0!");}
        TCObject object = objectDao.getTCObjectbyId(objectId);
        if(object == null){throw new BusinessException("找不到需要更新的对象！");}
        LoginUser user = loginService.getCurrentUser();
        if(!admin.getAccount().equals(user.getName())){
            if(!user.getCompanyId().equals(object.getCompanyId())){
                throw new BusinessException("该对象非本公司数据，无权限修改！");
            }
        }


        if(StringUtils.isNotBlank(objectCode) && !objectCode.equals(object.getObjectCode())){
            if( this.isExistObjectCode(objectCode,object.getCompanyId())) {
                throw new BusinessException("数据库中已经存在"+objectCode+"的编码!");
            }
            object.setObjectCode(objectCode);
        }
        if(StringUtils.isNotBlank(objectName)){
            object.setObjectName(objectName);
        }
        if(state != null){
            object.setState(state);
        }
        if(updateType != ObjectTypeEnum.NONE){
            if(object.getType() != updateType.getType()){throw new BusinessException("更新的操作类型错误！");}
        }
        objectDao.updateObject(object);
        return object;
    }


    /**
     * 将此保存方法私有，防止外部调用，只提供saveObjectSonType,saveObjectFatherType两个方法来保证数据的安全性
     * @param objectCode
     * @param objectName
     * @param parentId
     * @param type
     * @param state
     * @return
     * @throws ObjectServiceException
     * @throws BusinessException
     */
    private TCObject saveObject(String objectCode,String objectName,int parentId,int type,int state,int companyId) throws ServiceException,BusinessException {
        TCObject object = new TCObject();
        object.setObjectCode(objectCode);
        object.setObjectName(objectName);
        object.setParentId(parentId);
        object.setType(type);
        object.setState(state);
        object.setHasChildren(0);
        object.setCompanyId(companyId);
        this.prepareSaveObject(object, parentId);
        ObjectUtils.validSaveObject(object);

        if(objectDao.saveTCObject(object) > 0){
            return object;
        }else{
            throw new ObjectServiceException("Error: save TCObject faild! info:"+ JSONObject.fromObject(object).toString());
        }

    }

    @Transactional(propagation = Propagation.REQUIRED,readOnly = true)
    public List<TCObject> findbyAsyncTree(int parentId,int pagesize,int page)throws ObjectServiceException{
        int count = objectDao.countFindByAsyncTree(parentId);
        int maxPage = PageUtils.getMaxPage(count,pagesize) ;
        if(maxPage == 0){maxPage++;}
        if(parentId < 0){
            throw new ObjectServiceException("parentId must be greater than 0.");
        }
        if(page <= 0){
            throw new ObjectServiceException("page must be greater than 0.");
        }else if(page > maxPage){
            throw new ObjectServiceException("page must be less than "+maxPage+".");
        }
        int start = PageUtils.getNumberStart(page,pagesize);
        return objectDao.findByAsyncTree(parentId,start,pagesize);
    }



    /**
     * 查找是否存在相同的objectCode
     * @param objectCode
     * @return
     * @throws ObjectServiceException
     */
    public boolean isExistObjectCode(String objectCode,int companyId) throws ObjectServiceException{
        if(StringUtils.isBlank(objectCode)){throw new ObjectServiceException("Invalid objectCode parameter!");}
        int result = objectDao.existObjectCode(objectCode,companyId);
        if(result == 0){return false;}

        return true;
    }


    /**
     * 用来保存TCObject 的准备工作<br>
     *     生成position,generation,totalcode<br>
     *     修改父级TCObject 的 hasChildren
     * @param object
     * @param parentId
     * @throws ObjectServiceException
     * @throws BusinessException
     */
    private void prepareSaveObject(TCObject object,int parentId) throws ServiceException,BusinessException{
        if(object == null){throw new ObjectServiceException("Invalid object!");}
        if(this.isExistObjectCode(object.getObjectCode(),object.getCompanyId())){throw new BusinessException("数据库中存在"+object.getObjectCode()+"编码！");}

        String position = ObjectUtils.nextPosition(objectDao.findCurrentPositionByParentId(parentId));
        int generation = 1;
        String totalCode = position;

        if(parentId != 0 ){
            TCObject parent = objectDao.getTCObjectbyId(parentId);
            totalCode = parent.getTotalCode()+','+position;
            generation = parent.getGeneration() + 1;
            //修改父级的hasChildren属性
            if(parent.getHasChildren() == 0) {
                objectDao.updateTCObjectHasChildren(parentId, 1);
            }
            if(parent.getType().equals(ObjectTypeEnum.SON.getType())){
                throw new BusinessException("添加的对象父级必须为文件夹!");
            }
        }

        object.setTotalCode(totalCode);
        object.setPosition(position);
        object.setGeneration(generation);

    }

    public List<ObjectDTO> searchObjectTreeWidthCompanyId(String search, Collection<String> totalCodes, int companyId) throws ServiceException{
        return objectDao.searchObjectTreeWidthCompanyId(search,totalCodes,companyId);
    }

    public List<ObjectDTO> searchObjectTreeByParentIdWidthCompanyId(int parentId,int companyId) throws ServiceException{
        return objectDao.searchObjectTreeByParentIdWidthCompanyId(parentId,companyId);
    }

    public List<TCObject> findObjectByCodes(Collection<String> objectCodes,int companyId) throws ServiceException{
        return objectDao.findObejctByCodesWidthCompanyId(objectCodes,companyId);
    }
}
